home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
monitory
/
amyload
/
device.a
< prev
next >
Wrap
Text File
|
1987-11-15
|
15KB
|
654 lines
*
* Load Device by Jeff Kelley
*
* You may give this software to anyone you please. If you sell it for
* a profit, you'll just have to live with your conscience.
*
* (in W.W. Howe V1.0.2 Assembler)
*
LOAD_TASK_PRIORITY EQU 25
LOAD_PRIORITY EQU 0
MICROSPERSEC EQU 1000000
INTERVAL EQU 5 ; Default time interval length in seconds (sample period)
TICKS EQU 61 ; Default number of ticks (when samples are taken) per interval
INCLUDE "exec/types.i"
INCLUDE "exec/nodes.i"
INCLUDE "exec/lists.i"
INCLUDE "exec/ports.i"
INCLUDE "exec/libraries.i"
INCLUDE "exec/devices.i"
INCLUDE "exec/memory.i"
INCLUDE "exec/io.i"
INCLUDE "exec/resident.i"
INCLUDE "exec/tasks.i"
INCLUDE "exec/errors.i"
INCLUDE "exec/initializers.i"
INCLUDE "exec/semaphores.i"
INCLUDE "exec/execbase.i"
INCLUDE "hardware/dmabits.i"
INCLUDE "hardware/custom.i"
INCLUDE "devices/timer.i"
INCLUDE "devices/load.i"
INCLUDE "asmsupp.i"
INCLUDE "macros.i"
XLIB OpenDevice
XLIB OpenLibrary
XLIB AddDevice
XLIB AddTask
XLIB CloseDevice
XLIB Signal
XLIB Remove
XLIB RemTask
XLIB PutMsg
XLIB GetMsg
XLIB ReplyMsg
XLIB Wait
XLIB DoIO
XLIB AvailMem
XLIB FreeMem
XLIB Disable
XLIB Enable
XLIB Forbid
XLIB Permit
XLIB AllocSignal
XLIB InitSemaphore
XLIB ObtainSemaphore
XLIB ReleaseSemaphore
XLIB SetTaskPri
XREF _AbsExecBase
XREF _custom
SECTION load.device,CODE
FirstAddress:
CLEAR d0
rts
initDDescrip:
DC.W RTC_MATCHWORD
DC.L initDDescrip
DC.L EndCode
DC.B RTF_AUTOINIT
DC.B VERSION
DC.B NT_DEVICE
DC.B LOAD_PRIORITY
DC.L LoadName
DC.L idString
DC.L Init
VERSION EQU 1
REVISION EQU 0
TimerName TIMERNAME
LoadName LOADNAME
idString:
DC.B 'load.device 1.0 (16 October 1987)',13,0
Init:
DC.L LD_SIZE
DC.L funcTable
DC.L dataTable
DC.L initRoutine
funcTable:
DC.L Open
DC.L Close
DC.L Expunge
DC.L FirstAddress ; Null Command (reserved for expansion)
DC.L BeginIO
DC.L AbortIO
DC.L -1
dataTable:
INITBYTE LN_TYPE,NT_DEVICE
INITLONG LN_NAME,LoadName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,idString
DC.L 0
*********************************************************************
*
* InitRoutine - initialize the load device structure
*
* D0 = Device Pointer
* A0 = Segment List
* A6 = SysBase
* If this routine returns non-zero, it will be linked into system
* device list.
initRoutine:
move.l a5,-(sp)
movea.l d0,a5 ; get device pointer into safe register
move.l a0,LD_seglist(a5)
move.l a6,LD_sysbase(a5)
* Initialize the Message Port.
lea LD_Port(a5),a0
move.l #LoadName,LN_NAME(a0)
move.b #NT_MSGPORT,LN_TYPE(a0)
move.b #PA_IGNORE,MP_FLAGS(a0)
lea MP_MSGLIST(a0),a0
NEWLIST a0
move.w #INTERVAL,LD_Interval(a5)
move.w #TICKS,LD_Ticks(a5)
move.l a6,-(sp)
movea.l a5,a6
bsr ComputeDelay
move.l (sp)+,a6
* Initialize the semaphore.
lea LD_Semaphore(a5),a0
CALLSYS InitSemaphore ; InitSemaphore(signalSemaphore)
; A0
lea LD_Semaphore(a5),a0
CALLSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
; A0
* Compute the maximum MEMF_CHIP and MEMF_FAST
move.l MemList+LH_HEAD(a6),a0 ; get pointer to first MemHeader node
DO addmemory
move.l (a0),d1 ; check LN_SUCC
UNTIL eq,addmemory
move.l MH_UPPER(a0),d0
sub.l MH_LOWER(a0),d0
btst #MEMB_CHIP,MH_ATTRIBUTES+1(a0)
IF ne,chipmemory
add.l d0,LD_Max_Chip(a5)
ELSE chipmemory
add.l d0,LD_Max_Fast(a5)
FI chipmemory
move.l d1,a0
OD addmemory
* Create the Load Device task.
lea LD_TaskCB(a5),a1
move.b #NT_TASK,LN_TYPE(a1)
move.b #LOAD_TASK_PRIORITY,LN_PRI(a1)
move.l #LoadName,LN_NAME(a1)
lea LD_Stack(a5),a0
move.l a0,TC_SPLOWER(a1)
add.l #LOAD_STACK_SIZE,a0
move.l a0,TC_SPUPPER(a1)
move.l a0,TC_SPREG(a1)
lea TC_MEMENTRY(a1),a0
NEWLIST a0
lea Task_Start,a2
movea.l #0,a3
CALLSYS AddTask ; AddTask(taskCB, initialPC, finalPC)
; A1 A2 A3
move.l a5,d0 ; Return device pointer
move.l (sp)+,a5 ; restore a5
rts
***************************************************************************
*
* Open
*
* A6 = Device
* A1 = IOB
* D0 = Unit Number
* D1 = Flags
* Return: Set IO_ERROR Field to indicate success/errno
Open:
btst #LDB_OPEN_EXCL,LD_flags(a6)
IF eq,shared_access_ok
btst #LDB_OPEN_EXCL,d1
IF ne,want_exclusive
tst.w LIB_OPENCNT(a6)
IF ne,device_in_use
move.b LDERR_IN_USE,IO_ERROR(a1)
rts
FI device_in_use
bset #LDB_OPEN_EXCL,LD_flags(a6)
FI want_exclusive
addq.w #1,LIB_OPENCNT(a6)
cmpi.w #1,LIB_OPENCNT(a6)
IF eq,startup
lea LD_Semaphore(a6),a0
LINKSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
; A0
FI startup
move.w LD_Interval(a6),LV_INTERVAL(a1)
move.w LD_Ticks(a6),LV_TICKS(a1)
move.b LD_TaskCB+LN_PRI(a6),LV_PRI(a1)
clr.b IO_ERROR(a1)
ELSE shared_access_ok
move.b #LDERR_ACCESS_DENIED, IO_ERROR(a1)
FI shared_access_ok
rts
***************************************************************************
*
* Close
*
* A6 = Device
* A1 = IOB
* Return: If the device is no longer open and a delayed expunge is pending,
* do the expunge and return the segment list. Else return NULL.
Close:
clr.l IO_DEVICE(a1)
subq.w #1,LIB_OPENCNT(a6)
IF eq,do_close
lea LD_Semaphore(a6),a0
LINKSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
; A0
bclr #LDB_OPEN_EXCL,LD_flags(a6)
btst #LIBB_DELEXP,LIB_FLAGS(a6)
IF ne,go_expunge
bra.s Expunge
FI go_expunge
FI do_close
CLEAR d0
rts
****************************************************************************
*
* Expunge
*
* A6 = Device
* Return: If the device is no longer open return seg list. Else set
* delayed Expunge flag and return NULL.
Expunge:
move.l a5,-(sp)
move.l a6,a5
move.l LD_sysbase(a5),a6
* Check to see if anyone has us open
tst.w LIB_OPENCNT(a5)
IF ne,still_open
* It is still open, set delayed Expunge flag
bset #LIBB_DELEXP,LIB_FLAGS(a5)
CLEAR d0
ELSE still_open
* Go ahead and get rid of us.
move.l LD_seglist(a5),-(a7) ; We need to return this value
* Unlink from device list.
movea.l a5,a1
CALLSYS Remove ; Remove(node)
; A1
* Remove the load.device task
lea LD_TaskCB(a5),a1
CALLSYS RemTask ; RemTask(taskCB)
; A1
* Close the timer device.
lea LD_TimerRequest(a5),a1
CALLSYS CloseDevice ; CloseDevice(ioRequest)
; A1
* Free the memory allocated to the library.
CLEAR d0
movea.l a5,a1
move.w LIB_NEGSIZE(a5),d0
sub.w d0,a1
add.w LIB_POSSIZE(a5),d0
CALLSYS FreeMem ; FreeMem(memBlock, byteSize)
; A1 D0
move.l (a7)+,d0
FI still_open
move.l a5,a6
move.l (sp)+,a5
rts
*************************************************************************
*
* BeginIO
*
* A6 = Device
* A1 = IOB
BeginIO:
clr.b IO_ERROR(a1)
move.w IO_COMMAND(a1),d0
asl.w #2,d0 ; Compute displacement
lea cmdtable(pc),a0
add.w d0,a0
* cmpa.l #cmdtable_end,a0 ; Check to make sure it's in range.
* (Assembler doesn't handle it right, so...)
dc.w $B1FC
dc.l cmdtable_end
bcs.s cmd_ok ; branch if a0 < #cmdtable_end
lea cmdtable(pc),a0 ; Get the address of CMD_INVALID
cmd_ok:
movea.l (a0),a0
jmp (a0)
****************************************************************************
*
* AbortIO
*
* A6 = Device
* A1 = IOB
AbortIO:
* Scan list for the IOB node
LINKSYS Forbid
move.l LD_Port+MP_MSGLIST+LH_HEAD(a6),d1
DO scanlist
movea.l d1,a0
move.l (a0),d1 ; get LN_SUCC
beq.s not_found
cmpa.l a0,a1
WHILE ne,scanlist
OD scanlist
move.l a1,d1
REMOVE a1 ; Remove the IOB node from the list.
LINKSYS Permit
movea.l d1,a1
move.b #IOERR_ABORTED,IO_ERROR(a1)
rts
not_found:
LINKSYS Permit
clr.b IO_ERROR(a1) ; Indicate an error occurred.
rts
cmdtable:
DC.L Invalid
DC.L Reset
DC.L Read
DC.L Write
DC.L Update
DC.L Clear
DC.L Stop
DC.L Start
DC.L Flush
DC.L Set
cmdtable_end:
*******************************************************************
*
* A6 = device
* A1 = IOB
Write:
Update:
Clear:
Invalid:
move.b #IOERR_NOCMD,IO_ERROR(a1)
rts
Read:
* If IO_QUICK is set, get the most recent values and return, do not reply.
* Otherwise, queue the IO request. Return. Reply will come later.
btst #IOB_QUICK,IO_FLAGS(a1)
IF ne,do_quickio
move.l LD_CPU(a6),LV_CPU(a1)
move.l LD_BLITTER(a6),LV_CPU(a1)
move.l LD_CHIP(a6),LV_CHIP(a1)
move.l LD_FAST(a6),LV_FAST(a1)
ELSE do_quickio
lea LD_Port(a6),a0
LINKSYS PutMsg ; PutMsg(msgPort, message)
FI do_quickio ; A0 A1
rts
Stop:
LINKSYS Forbid
tst.b LD_stop_count(a6)
IF eq,stop_load_task
lea LD_Semaphore(a6),a0
LINKSYS ObtainSemaphore
FI stop_load_task
addq.b #1,LD_stop_count(a6)
LINKSYS Permit
rts
Start:
tst.b LD_stop_count(a6)
IF eq,not_stopped
move.b #LDERR_NOT_STOPPED,IO_ERROR(a1)
ELSE not_stopped
LINKSYS Forbid
subq.b #1,LD_stop_count(a6)
IF eq,start_load_task
lea LD_Semaphore(a6),a0
LINKSYS ReleaseSemaphore
FI start_load_task
LINKSYS Permit
FI not_stopped
rts
* Reply to all pending requests, setting IOERR_ABORTED.
Flush:
LINKSYS Forbid
DO flushrequests
lea LD_Port(a6),a0
LINKSYS GetMsg ; message = GetMsg(msgPort)
tst.l d0 ; D0 A0
UNTIL eq,flushrequests
movea.l d0,a1
move.b #IOERR_ABORTED,IO_ERROR(a1)
LINKSYS ReplyMsg ; ReplyMsg(message)
; A1
OD flushrequests
LINKSYS Permit
rts
Reset:
; Set default values.
move.w #INTERVAL,LV_INTERVAL(a1)
move.w #TICKS,LV_TICKS(a1)
move.b #LOAD_TASK_PRIORITY,LV_PRI(a1)
; FALLTHROUGH into the Set command
Set:
move.l a1,-(sp)
lea LD_Semaphore(a6),a0
LINKSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
; A0
move.l (sp)+,a1
move.w LV_INTERVAL(a1),LD_Interval(a6)
move.w LV_TICKS(a1),LD_Ticks(a6)
bsr.s ComputeDelay
move.b LV_PRI(a1),d0
lea LD_TaskCB(a6),a1
LINKSYS SetTaskPri ; oldPriority = SetTaskPri(taskCB, newpriority)
; D0.b A1 D0.b
lea LD_Semaphore(a6),a0
LINKSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
; A0
rts
***************************************************************************
*
* ComputeDelay subroutine - From the LD_Interval and LD_Ticks, compute the
* delay in seconds and microseconds between ticks.
*
* Input: A6 - Load Device
* LD_Interval(a6) - Interval in seconds
* LD_Ticks(a6) - Number of Ticks per Interval
*
* Output: LD_secs(a6) - delay in seconds
* LD_micro(a6) - delay in microseconds
*
* Destroys: a0,d0,d1
*
ComputeDelay:
move.l d2,-(a7)
CLEAR d1
move.w LD_Interval(a6),d1 ; INTERVAL in seconds
move.w LD_Ticks(a6),d2 ; number of TICKS per INTERVAL
mulu #20,d1 ; multiply d0 by a MICROSPERSEC
mulu #50000,d1 ; (in 2 steps, since can't mult by >65536)
* d1.l = d1.l / d2.w
movea.w d1,a0
clr.w d1
swap d1
divu d2,d1
move.l d1,d0
swap d1
move.w a0,d0
divu d2,d0
move.w d0,d1
* LD_secs = d1.l / MICROSPERSEC
* LD_micro = d1.l % MICROSPERSEC
clr.l LD_secs(a6)
DO incrsecs
cmp.l #MICROSPERSEC,d1
WHILE ge,incrsecs
sub.l #MICROSPERSEC,d1
addi.l #1,LD_secs(a6)
OD incrsecs
move.l d1,LD_micro(a6)
move.l (a7)+,d2
rts
********************************************************************
*
* Load Task
*
* Register Usage: a6 : SysBase
* a2 : Semaphore
* a3 : TimerPort
* a4 : TimerMessage
* a5 : LoadDevice
*
* d2 : Current Tick count
* d3 : Ready Queue counter
* d4 : Blitter Use counter
* d5 : Chip Mem available
* d6 : Fast Mem available
* d7 : <Free Safety>
* To get a pointer to the Load Device structure, use a7 as a base.
* It points to the last longword of the stack (which contains the
* address of a cleanup routine).
* a7
* | <---------- LD_Stack -----------> | <- LOAD_STACK_SIZE - 4 -> |
* |----------------------------------------------------------------------|
* | Load Device | TimerRequest | etc. | Stack |
* |----------------------------------------------------------------------|
Task_Start:
move.l _AbsExecBase,a6
lea -LD_Stack-LOAD_STACK_SIZE+4(a7),a5 ; Get Load Device ptr
lea LD_Semaphore(a5),a2
* Initialize the Timer Port.
lea LD_TimerPort(a5),a3
move.b #NT_MSGPORT,LN_TYPE(a3)
move.b #PA_SIGNAL,MP_FLAGS(a3)
moveq.l #-1,d0
CALLSYS AllocSignal ; signalNum = AllocSignal(signalNum)
move.b d0,MP_SIGBIT(a3) ; D0 D0
lea LD_TaskCB(a5),a0
move.l a0,MP_SIGTASK(a3)
lea MP_MSGLIST(a3),a0
NEWLIST a0
* Initialize the timer IO request
lea LD_TimerRequest(a5),a4
move.b #NT_MESSAGE,LN_TYPE(a4)
move.l a3,MN_REPLYPORT(a4)
move.w #IOTV_SIZE,MN_LENGTH(a4)
* Open the timer.device
lea TimerName,a0
movea.l a4,a1
moveq.l #UNIT_VBLANK,d0
CLEAR d1
CALLSYS OpenDevice ; error = OpenDevice(Name,Unit,ioRequest,flags)
; D0 A0 D0 A1 D1
DO mainloop
move.l a2,a0
CALLSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
move.w LD_Ticks(a5),d2 ; A0
moveq.l #0,d3
moveq.l #0,d4
* 'tickloop' is done once for each 'tick'.
DO tickloop
move.w #TR_ADDREQUEST,IO_COMMAND(a4)
move.l LD_secs(a5),IOTV_TIME+TV_SECS(a4)
move.l LD_micro(a5),IOTV_TIME+TV_MICRO(a4)
movea.l a4,a1
CALLSYS DoIO ; error = DoIO(ioRequest)
; D0 A1
* Compute System Statistics:
* Measure length of ready queue
* Note: LoadTask is not in this queue, since we are running.
CALLSYS Disable
movea.l TaskReady+LH_HEAD(a6),a1 ; Get Pointer to first
DO readycount ; node into a1.
move.l (a1),d0 ; Look ahead.
UNTIL eq,readycount
addq.l #1,d3
movea.l d0,a1
OD readycount
CALLSYS Enable
* Check if blitter busy
* move.w _custom+dmaconr,d0 ; Assembler can't handle this...
move.w $DFF002,d0
btst #DMAB_BLTDONE,d0
IF ne,busy
addq.l #1,d4
FI busy
subq.w #1,d2 ; Decrement tick count
UNTIL eq,tickloop
OD tickloop
* Compute available memory
move.l #MEMF_CHIP,d1
CALLSYS AvailMem ; size = AvailMem(requirements)
move.l LD_Max_Chip(a5),d5 ; D0 D1
sub.l d0,d5
move.l #MEMF_FAST,d1
CALLSYS AvailMem ; size = AvailMem(requirements)
move.l LD_Max_Fast(a5),d6 ; D0 D1
sub.l d0,d6
move.l d3,LD_CPU(a5)
move.l d4,LD_BLITTER(a5)
move.l d5,LD_CHIP(a5)
move.l d6,LD_FAST(a5)
DO reply
lea LD_Port(a5),a0
CALLSYS GetMsg ; message = GetMsg(msgPort)
tst.l d0 ; D0 A0
UNTIL eq,reply
movea.l d0,a1
move.l d3,LV_CPU(a1)
move.l d4,LV_BLITTER(a1)
move.l d5,LV_CHIP(a1)
move.l d6,LV_FAST(a1)
CALLSYS ReplyMsg ; ReplyMsg(message)
OD reply ; A1
lea LD_Semaphore(a5),a0
CALLSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
ODL mainloop ; A0
EndCode:
END